#ifndef _COM_FACTORY_HPP_
#define _COM_FACTORY_HPP_

#include <crt_util.h>
#include <dlcom/ibase.h>
#include <dlcom/comfunc.hpp>
#include <dlcom/comsentry.hpp>

uvStdComNameSpaceBegin

	class CNullObjcetUnkown :	public	IBase,
								public	CUnknownImp
	{
	public:
		BEGIN_STDCOM_MAP
			STDCOM_INTERFACE_ENTRY_UNKNOWN
		END_STDCOM_MAP
	};

	typedef struct _STDCOM_OBJMAP_ENTRY{ 

		CLSID clsid; 
		HRESULT (*pfnGetClassObject)(const IID&, void**);
		char ProgID[MAX_PROGIDLEN];
		ULONG addr;
	}STDCOM_OBJMAP_ENTRY, *pSTDCOM_OBJMAP_ENTRY;


template<class CLS, class IFactory = IComClassFactory>
class CoClassFactory : public IFactory, public CUnknownImp
{
public: 
	BEGIN_STDCOM_MAP
		STDCOM_INTERFACE_ENTRY(IComClassFactory);
	END_STDCOM_MAP

public:

	std_method_(HRESULT, CreateInstance)(IBase *pUnkOuter, REFIID riid, void **ppvObject)
	{
		return create_instance(pUnkOuter, riid, ppvObject);
	}
	std_method_(HRESULT, LockServer)(int fLock)
	{
		return lock_server(fLock);
	}
public:
	static HRESULT create_instance(IBase *punkOuter, REFIID riid, void **ppv)
	{
		*ppv = 0;
		rc_assert( !punkOuter || IID_IBase == riid, E_INVALIDARG);

		SafePtr<CLS*> p = new CLS();
		rc_assert(p, E_OUTOFMEMORY);

		p.m_p->AddRef(); 
		HRESULT hr = p.m_p->QueryInterface(riid, ppv);
		p.detach()->Release(); 
		return hr;
	}
	static HRESULT lock_server(int /*fLock*/)
	{
		return S_OK;
	}
	static HRESULT GetClassObject(const IID& riid, void **ppv)
	{
		return CoClassFactory<CoClassFactory<CLS> >::create_instance(0, riid, ppv);
	}
};

template<class CLS>
class CoComFactoryCreator : public CoClassFactory<CLS, IComObjectFrameworkClassFactory>
{
public: 
	BEGIN_STDCOM_MAP
		STDCOM_INTERFACE_ENTRY(IComObjectFrameworkClassFactory);
		STDCOM_INTERFACE_ENTRY(IComClassFactory);
	END_STDCOM_MAP
public: 
	std_method(CreateInstance)(IBase *prot, IBase *punkOuter, REFIID riid, void **ppv)
	{
		return create_instance(prot, punkOuter, riid, ppv);
	}
public:
	static HRESULT create_instance(IBase *prot, IBase *punkOuter, REFIID riid, void **ppv)
	{
		*ppv = 0;
		rc_assert(!punkOuter || IID_IBase == riid, E_INVALIDARG);

		SafePtr<CLS*> p = new CLS();
		rc_assert(p, E_OUTOFMEMORY);
		p.m_p->AddRef();
		HRESULT hr = p.m_p->QueryInterface(riid, ppv);
		p.detach()->Release(); 
		return hr;
	}
	static HRESULT GetClassObject(const IID& riid, void **ppv)
	{
		return CoComFactoryCreator<CoComFactoryCreator<CLS> >::create_instance(0, 0, riid, ppv);
	}
};

																			
uvStdComNameSpaceEnd


#endif 
